home *** CD-ROM | disk | FTP | other *** search
- NAME mssscp
- ; File MSSSCP.ASM
- include mssdef.h
- ; Copyright (C) 1985, 1993, Trustees of Columbia University in the
- ; City of New York. Permission is granted to any individual or institution
- ; to use this software as long as it is not sold for profit. This copyright
- ; notice must be retained. This software may not be included in commercial
- ; products without written permission of Columbia University.
- ;
- ; Edit History
- ; 27 August 1992 version 3.13
- ; 6 Sept 1991 version 3.11
- ; Last edit 19 Jan 1993
- ; 4 June 1991 Make label searches be global so the next higher level is
- ; searched if the present level does not contain the target.
- ; 6 June 1989 Limit echoing of received chars by OUTPUT to 100, to quench
- ; verbose hosts. From Dan Norstedt.
- ; 4 May 1989 Make input/reinput scan buffer be allocated dynamically. Allow
- ; for that size to be set via Environment as Kermit initializes.
- ;
- ; MS Kermit Script routines, DEC-20 style.
- ; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
- ;;
- ; Created June, 1986 a.d. By James Sturdevant
- ; A. C. Nielsen Co. Mpls.
- ; 8401 Wayzata Blvd.
- ; Minneapolis, Mn. 55426
- ; (612)546-0600
- ;;;;;;;;
- ; Kermit command level usages and this file's entry points:
- ; Clear - clears serial port buffers. Procedure scclr.
- ; Echo text - displays text on local screen. Proc scecho.
- ; Pause [time] - waits indicated number of seconds (default is Input
- ; Default-timeout, 1 second typically). Proc scpau.
- ; IF condtion command - tests condition (SUCCESS or FAILURE just now) and
- ; if the condition is met executes the main-line Kermit command.
- ; GOTO label - rewinds Take file or Macro, locates the :label, transfers
- ; parsing control to the next line.
- ; Input [time] text - waits up to time seconds while scanning serial port
- ; input for a match with text. Default value for time is Input
- ; Default-timeout, 1 second typically). Spaces or tabs are separators
- ; between the time and text fields. Proc scinp.
- ; A carriage return typed by the local user simulates a match.
- ; Reinput [time] text - like INPUT but non-destructively rereads the 128 byte
- ; script buffer. Buffer can be added to, until full, if necessary.
- ; Output text - sends the text to the serial output port. Proc scout.
- ; Transmit text [prompt] - raw file transfer to host. Proceeds from source
- ; line to source line upon receipt of prompt from host or carriage
- ; return from us. Default prompt is linefeed. A null prompt (\0)
- ; causes the file to be sent with no pausing or handshaking. Note
- ; that linefeeds are stripped from outgoing material. Proc scxmit.
- ; In the above commands "text" may be replaced by "@filespec" to cause the
- ; one line of that file to be used instead. @CON obtains one line of
- ; text from the keyboard. Such "indirect command files" may be nested
- ; to a depth of 100. Control codes are written as decimal numbers
- ; in the form "\ddd" where d is a digit between 0 and 9. Carriage
- ; return is \13, linefeed is \10, bell is \7; the special code \255
- ; is used to match (Input) either cr or lf or both.
- ; These commands can be given individually by hand or automatically
- ; in a Kermit Take file; Take files may be nested.
- ;;;;;;;;
- ; These routines expect to be invoked by the Kermit command dispatcher
- ; and can have their default operations controlled by the Kermit Set Input
- ; command (implemented in file mssset.asm). They parse their own cmd lines.
- ; Set Input accepts arguments of
- ; Case Ignore or Observe (default is ignore case when matching strings)
- ; Default-timeout seconds (default is 5 seconds)
- ; Echo On or Off controls echoing of Input cmd text (default is Off)
- ; Timeout-action Quit or Proceed (default is Proceed)
- ; These conditions are passed via global variables script.incasv, .indfto,
- ; .inecho, .inactv, respectively, stored here in structure script.
- ;;;;;;;;;
-
- public script, scout, scinp, scpau, scecho, scclr, scxmit, scwait
- public sgoto, screinp, ifcmd, setalrm, inptim, chktmo, alrhms
- public buflog, scpini, scpbuflen, decvar, incvar, scmpause, outpace
-
- linelen equ 134 ; length of working buffer line
- maxtry equ 5 ; maximum number of output retries
- stat_unk equ 0 ; status return codes.
- stat_ok equ 1 ; have a port character
- stat_cc equ 2 ; control-C typed
- stat_tmo equ 4 ; timeout
- stat_cr equ 8 ; carriage return typed
-
- ifsuc equ 0 ; indicators for IF conditions
- iffail equ 1
- ifext equ 2
- iferr equ 3
- ifnot equ 4
- ifctr equ 5
- ifmdf equ 6
- ifalarm equ 7
- ifequal equ 8
- ifless equ 9
- ifsame equ 10
- ifmore equ 11
- ifllt equ 12
- iflgt equ 13
- ifpath equ 14
-
- data segment
- extrn taklev:byte, takadr:word, portval:word, flags:byte
- extrn rxtable:byte, spause:byte, errlev:byte, fsta:word
- extrn kstatus:word, mcctab:byte, comand:byte, ttyact:byte
- extrn keyboard:word, rdbuf:byte, apctrap:byte
-
- ; global (public) variables
- script scptinfo <> ; global structure, containing:
- ;;inactv db 0 ; input action value (default proceed)
- ;;incasv db 0dfh ; input case (default ignore)
- ;;indfto dw 1 ; input and pause timeout (def 1 sec)
- ;;inecho db 1 ; echo Input cmd text (0 = no)
- ;;xmitfill db 0 ; non-zero to TRANSMIT filler
- ;;xmitlf db 0 ; non-zero to TRANSMIT LF's
- ;;xmitpmt db lf ; prompt between lines
-
- ; local variables
- line db linelen+1 dup (0) ; line of output or input + terminator
- even
- scpbuflen dw 128 ; serial port local buffer def length
- bufcnt dw 0 ; serial port buf byte cnt, must be 0
- bufseg dw 0 ; segment of buffer
- bufrdptr dw 0 ; serial port buf read ptr
- bufwtptr dw 0 ; serial port buf write ptr
- bufpkptr dw 0 ; peek-read pointer
- bufpkcnt dw 0 ; peek-read byte count remaining
- inplen dw 0 ; length of input match string
- reinflg db 0 ; 0 = INPUT, else REINPUT command
- notflag db 0 ; IF NOT flag
- slablen dw 0 ; label length, for GOTO
- status dw 0 ; general status word
- fhandle dw 0 ; file handle storage place
- temptr dw 0 ; temporary pointer
- temptr2 dw 0 ; ditto, points to end of INPUT string
- tempd dw 0 ; temp
- temp dw 0 ; a temp
- tempa db 0 ; another temp
- wtemp db 0 ; temp for WAIT
- ltype db 0 ; lex type for IF statements
- retry db 0 ; number of output retries
- parmsk db 7fh ; 7/8 bit parity mask
- lecho db 0 ; local echo of output (0 = no)
- timout dw 0 ; work area (seconds before timeout)
- timhms db 4 dup (0) ; hhmmss.s time of day buffer
- alrhms db 4 dup (0) ; hhmmss.s time of day alarm buffer
- outpace dw 0 ; OUTPUT pacing, millisec
- eolchr db LF ; end of line character
-
- crlf db cr,lf,'$'
- xfrfnf db cr,lf,'?Transmit file not found$'
- xfrrer db cr,lf,'?error reading Transmit file$'
- xfrcan db cr,lf,'?Transmission canceled$'
- indmis db '?Indirect file not found',cr,lf,'$'
- inderr db '?error reading indirect file',cr,lf,'$'
- laberr db cr,lf,'?Label ":$'
- laberr2 db '" was not found.',cr,lf,'$'
- tmomsg db cr,lf,'?Timeout',cr,'$'
- outhlp db 'line of text to be sent to remote host$'
- inphlp db 'time-limit and line of text expected from remote host'
- db cr,lf,' Time is number of seconds or until a specific'
- db ' hh:mm:ss (24 hour clock)$'
- echhlp db 'line of text to be Echoed to screen$'
- ptshlp db 'amount of time to pause/wait'
- db cr,lf,' Time is number of seconds or until a specific'
- db ' hh:mm:ss (24 hour clock)$'
- wthlp db cr,lf,'Optional modem status signals CD, CTS, DSR, RI which'
- db ' if asserted',cr,lf,' will terminate waiting$'
- wtbad db cr,lf,'?Command not understood, improper syntax$'
- xmthlp db ' Name of file to be Transmitted$'
- pmthlp db cr,lf
- db ' Prompt character expected as an ACK from host (\0 for none)$'
- ifdfhlp db cr,lf,' Name of macro or variable then a command$'
- alrmhlp db cr,lf,' Seconds from now or time of day (HH:MM:SS) for alarm,'
- db ' < 12H from present$'
- mphlp db cr,lf,' Number of milliseconds to pause (0..65535)$'
- mpbad db cr,lf,'?Bad number$'
- ifmhlp db cr,lf,' Number, ARGC (1+argument count), COUNT, ERRORLEVEL,'
- db ' KEYBOARD, VERSION$'
- ifnhlp db cr,lf,' Number which errorlevel should match or exceed$'
- ifnmsg db cr,lf,'?Number expected, ignoring "$'
- ifnmsg2 db '"$'
- discard db ' Kermit command'
- db cr,lf,' "IF" condition is false, command will be ignored.$'
- ifehlp1 db cr,lf,'?pair of words or variables to be compared$'
- ifehlp2 db cr,lf,'?second word or variable to be compared$'
- chgvarhlp db 'name of variable$'
- ssizehlp db 'amount, default is 1$'
- clrhelp db cr,lf,' INPUT-BUFFER (script string matching buffer), or'
- db cr,lf,' DEVICE-BUFFER (comms receive), or BOTH$'
-
- clrtable db 3
- mkeyw "input-buffer",1
- mkeyw "device-buffer",2
- mkeyw "both",3
-
- iftable db 15 ; IF command dispatch table
- mkeyw 'Not',ifnot
- mkeyw '<',ifless
- mkeyw '=',ifsame
- mkeyw '>',ifmore
- mkeyw 'Alarm',ifalarm
- mkeyw 'Count',ifctr
- mkeyw 'Defined',ifmdf
- mkeyw 'Errorlevel',iferr
- mkeyw 'Equal',ifequal
- mkeyw 'Exist',ifext
- mkeyw 'Inpath',ifpath
- mkeyw 'LGT',iflgt
- mkeyw 'LLT',ifllt
- mkeyw 'Failure',iffail
- mkeyw 'Success',ifsuc
- data ends
-
- code segment
-
- extrn comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
- extrn cptchr:near, serini:near, pcwait:near, katoi:near, spath:near
- extrn cnvstr:near, getmodem:near, isdev:near, isfile:near
- extrn takrd:near, takclos:near, tolowr:near, prtasz:near,strlen:near
- extrn sendbl:near, dec2di:near
-
- assume cs:code, ds:data, es:nothing
-
- ; Initialize script routines before use, called as Kermit initializes.
-
- SCPINI PROC NEAR
- mov cx,scpbuflen ; (RE)INPUT buffer length
- mov bx,cx ; string length, in bytes
- add bx,15 ; round up
- jnc scpini1 ; nc = under max size
- scpini3:mov bx,0ffffh ; 64KB-16 bytes, max buffer
- scpini1:mov cl,4
- shr bx,cl ; convert to paragraphs (divide by 16)
- scpini2:mov cx,bx ; remember desired paragraphs
- mov ah,alloc ; allocate a memory block
- int dos
- jc scpini4 ; error, not enough memory
- mov bufseg,ax ; store new segment
- mov cl,4
- shl bx,cl ; convert paragraphs to bytes
- mov scpbuflen,bx ; new length
- push es
- mov es,ax ; buffer segment
- xor di,di ; offset
- mov cx,bx ; length in bytes
- shr cx,1 ; even, do words
- xor ax,ax ; null filler
- cld
- rep stosw ; clear the buffer
- pop es
- clc ; return success
- ret
- scpini4:mov scpbuflen,0
- stc ; carry set for failure to initialize
- ret
- SCPINI ENDP
-
- ; Clear input buffer(s) of serial port
- ; Clear command
- ;
- SCCLR PROC NEAR
- mov comand.cmcr,1 ; permit empty line
- mov ah,cmkey
- mov dx,offset clrtable
- mov bx,offset clrhelp
- call comnd
- mov comand.cmcr,0
- mov kstatus,kssuc ; global status
- push bx ; cmd return
- mov ah,cmeol ; get a confirm
- call comnd
- pop bx
- jnc scclr1 ; nc = success
- ret ; failure
- scclr1: cmp bx,1
- jne scclr2
- call bufclear
- clc
- ret
- scclr2: cmp bx,2
- jne scclr3 ; default, gibberish bx
- call clrbuf
- clc
- ret
- scclr3: call bufclear ; clear our serial port circular buf
- call clrbuf ; clear system serial port buffer too
- clc
- ret
- SCCLR ENDP
-
- ;
- ; Echo a line of text to our screen
- ; Echo text
- ;
- SCECHO PROC NEAR
- mov ah,cmline ; get a whole line of asciiz text
- mov bx,offset rdbuf ; where to store in
- mov word ptr [bx],0 ; clear line
- mov comand.cmblen,cmdblen ; set line capacity (length of rdbuf)
- mov dx,offset echhlp ; help
- call comnd
- jc echo3
- mov ah,cmeol
- call comnd
- jc echo3
- mov si,offset rdbuf ; start of line
- mov di,si ; convert to the same place
- mov ah,script.incasv ; save current case state
- push ax
- mov script.incasv,0ffh ; say no case conversion
- call cnvlin ; convert \numbers to binary
- pop ax
- mov script.incasv,ah ; recover case state
- jc echo3 ; carry set means error
- mov ah,prstr
- mov dx,offset crlf
- int dos
- jcxz echo2 ; z = nothing to show
- cld
- echo1: lodsb ; get a source char into al
- mov dl,al
- mov ah,conout
- int dos
- loop echo1 ; get another
- echo2: clc ; return success
- echo3: ret ; error
- SCECHO ENDP
-
- ; Extract label from command line. Store in LINE, length in slablen.
- ; Jump to line in Take or Macro following that label.
- SGOTO PROC NEAR
- mov kstatus,kssuc ; global status
- mov ah,cmword ; get a word
- mov dx,offset line ; buffer to hold label
- xor bx,bx ; no help (non-interactive command)
- mov slablen,bx ; clear label holding buffer
- mov comand.cmkeep,1 ; keep Take/macro open after EOF
- call comnd
- jnc goto1 ; nc = success
- ret ; failure
- goto1: mov ax,ax ; byte count
- mov slablen,ax ; save count here
- or ax,ax ; need contents
- jz goto3 ; empty, fail
- mov comand.cmkeep,1 ; keep Take file open after this call
- mov ah,cmeol
- call comnd
- jnc goto2 ; nc = success
- ret ; failure
- goto2: cmp flags.cxzflg,'C' ; check for Control-C breakout
- je goto3 ; e = yes, fail
- cmp taklev,0 ; in a Take file or Macro?
- jne GETTO ; ne = yes, find the label
- clc ; ignore interactive command
- ret
- goto3: stc
- ret
-
- ; Find line starting just after ":label". Label is in variable LINE
- ; (length in slablen). Readjust Take read pointer to start of that line.
- ; Performs file search from beginning of file, popping up levels if req'd.
- ; Exit carry clear if success, carry set otherwise. Local worker routine.
- getto proc near
- push bx ; global save of bx
- gett0: mov bx,takadr
- cmp [bx].taktyp,0feh ; get type of take (a file?)
- jne gett2 ; ne = no, a macro
- ; scan from start of Take file
- mov eolchr,LF ; file lines end on LF
- mov bx,[bx].takhnd ; rewind the file
- xor cx,cx
- xor dx,dx
- xor al,al ; zero displacement from start of file
- mov ah,lseek
- int dos
- jnc gett1
- jmp gett20 ; c = failure
- gett1: call takrd ; get a buffer of data
- mov bx,takadr ; restore bx to working value
- jmp short gett4
- ; Take a Macro
- gett2: mov eolchr,CR ; Macro lines end on CR
- mov cx,[bx].takbuf ; segment of macro definition
- push es
- mov es,cx
- mov cx,es:[0] ; get string length byte
- pop es
- mov [bx].takcnt,cx ; set unread to full buffer (rewind)
- mov [bx].takptr,2 ; set read pointer to start of text
-
- gett4: call getch ; get a character
- jc gett14 ; c = end of file, no char
- cmp al,' ' ; leading white space?
- je gett4 ; e = yes, read again
- cmp al,TAB
- je gett4
- cmp al,':' ; start of label?
- je gett8 ; e = yes
- gett6: cmp al,eolchr ; end of line?
- je gett4 ; e = yes, seek colon for label
- call getch ; get a character
- jc gett14 ; c = end of file, no char
- jmp short gett6 ; read until end of line
-
- gett8: mov si,offset line ; label to search for
- mov cx,slablen ; its length
- jcxz gett12 ; no chars to match
- cmp byte ptr[si],':' ; user label starts with colon
- jne gett10 ; ne = no
- inc si ; skip user's colon
- dec cx
- jcxz gett12 ; no chars to match
- gett10: call getch ; read file char into al
- jc gett14 ; c = end of file
- mov ah,al
- cld
- lodsb
- call tolowr ; convert al and ah to lower case
- cmp al,ah ; match?
- jne gett6 ; ne = no, goto end of line
- loop gett10 ; continue matching
- ; match obtained
- call getch ; read next file character
- jc gett13 ; c = end of file, no char
- cmp al,' ' ; separator?
- je gett12 ; e = yes, unique label found
- cmp al,TAB ; this kind of separator?
- je gett12 ; e = yes
- cmp al,eolchr ; or end of line?
- je gett13 ; e = yes
- cmp al,CR ; macro eol, also file start eol pair
- jne gett6 ; ne = longer label than target
-
- gett12: call getch ; read past end of line
- jc gett13 ; c = end of file, no char
- cmp al,eolchr ; end of line character?
- jne gett12 ; ne = no, keep reading
- gett13: pop bx
- clc ; return carry clear
- ret ; Take pointers are ready to read line
- ; failed to find label, pop a level
- gett14: call takclos ; close this macro/take file
- cmp taklev,0 ; still in macro/take?
- je gett15 ; e = no, quit
- jmp gett0 ; try next level up
- gett15:mov ah,prstr ; say label not found
- mov dx,offset laberr ; first part of error message
- int dos
- mov dx,offset line
- cmp line,':' ; label starts with ":"?
- jne gett16 ; ne = no
- inc dx ; yes, skip it
- gett16: call prtasz ; print asciiz string
- mov ah,prstr
- mov dx,offset laberr2 ; trailer of error message
- int dos
- gett20: pop bx
- mov kstatus,ksgen ; command status, failure
- stc ; set carry for failure
- ret
- getto endp
- SGOTO ENDP
-
- ; Read char from Take buffer. Returns carry clear and char in al, or if end
- ; of file returns carry set. Enter with BX holding takadr. Local worker.
- getch proc near
- cmp [bx].takcnt,0 ; buffer empty?
- jg getch2 ; g = no
- cmp [bx].taktyp,0feh ; file?
- jne getch1 ; ne = no, a macro
- call takrd ; read another buffer
- cmp [bx].takcnt,0 ; end of file?
- jne getch2 ; ne = no
- getch1: stc ; e = yes, exit error
- ret
- getch2: push si
- push es
- mov es,[bx].takbuf ; segment of buffer
- mov si,[bx].takptr ; read a char from Take buffer
- mov al,es:[si]
- inc si
- mov [bx].takptr,si ; move buffer pointer
- dec [bx].takcnt ; decrease number of bytes remaining
- pop es
- pop si
- clc ; return carry clear
- ret
- getch endp
-
-
- ; IF [NOT] {< }| = | > | ALARM | COUNT | FAILURE | SUCCESS | INPATH filespec
- ; | ERRORLEVEL \number | EQUAL string string | EXIST filespec} command
-
- IFCMD PROC NEAR
- mov notflag,0 ; assume NOT keyword is absent
- ifcmd1: mov ah,cmkey ; parse keyword
- mov dx,offset iftable ; table of keywords
- xor bx,bx ; help is the table
- call comnd
- jnc ifcmd1a ; nc = success
- ret ; failure
- ifcmd1a:cmp bx,ifnot ; NOT keyword?
- jne ifcmd2 ; ne = no
- xor notflag,1 ; toggle not flag
- jmp short ifcmd1 ; and get next keyword
-
- ifcmd2: cmp bx,ifsuc ; IF SUCCESS?
- jne ifcmd4 ; ne = no
- cmp kstatus,kssuc ; do we have success?
- je ifcmd2a ; e = yes
- jmp ifcmdf ; ne = no, no jump
- ifcmd2a:jmp ifcmdp ; yes
-
- ifcmd4: cmp bx,iferr ; IF ERRORLEVEL?
- jne ifcmd5 ; ne = no
- jmp ifnum ; parse number to binary in line
-
- ifcmd5: cmp bx,ifext ; IF EXIST filespec?
- je ifcmd5a ; e = yes
- cmp bx,ifpath ; IF INPATH filespec?
- jne ifcmd6 ; ne = no
- ifcmd5a:mov ah,cmword ; read a filespec
- mov dx,offset rdbuf ; buffer for filespec
- push bx ; save command kind
- xor bx,bx
- call comnd
- pop bx
- jnc ifcmd5b ; nc = success
- ret ; failure
- ifcmd5b:mov ax,offset rdbuf ; isfile wants pointer in ds:ax
- cmp bx,ifpath ; INPATH?
- je ifcmd5c ; e = yes
- call isfile ; see if file exists
- jc ifcmdf ; c = no
- jmp ifcmdp ; yes, do following command
- ifcmd5c:call spath ; search path
- jc ifcmdf ; c = no such file
- jmp ifcmdp ; yes, do following command
-
- ifcmd6: cmp bx,iffail ; IF FAIL?
- jne ifcmd7
- test kstatus,not (kssuc) ; check all bits
- jz ifcmdf ; z = not that condition, no jump
- jmp short ifcmdp
-
- ifcmd7: cmp bx,ifctr ; IF COUNT?
- jne ifcmd8 ; ne = no
- cmp taklev,0 ; in a Take file?
- je ifcmdf ; e = no, fail
- push bx
- mov bx,takadr ; current Take structure
- cmp [bx].takctr,0 ; exhausted count?
- je ifcmd7a ; e = yes, dec no more ye counter
- dec [bx].takctr ; dec COUNT if non-zero
- cmp [bx].takctr,0 ; exhausted now?
- je ifcmd7a ; e = yes
- pop bx
- jmp short ifcmdp ; COUNT > 0 at entry, execute command
- ifcmd7a:pop bx
- jmp short ifcmdf ; do not execute command
-
- ifcmd8: cmp bx,ifmdf ; IF DEF?
- jne ifcmd9 ; ne = no
- jmp ifmdef ; do further parsing below
-
- ifcmd9: cmp bx,ifalarm ; IF ALARM?
- jne ifcmd10 ; ne = no
- jmp ifalrm ; do further parsing below
-
- ifcmd10:cmp bx,ifequal ; IF EQUAL?
- jne ifcmd10a ; ne = no
- jmp ifequ ; do further parsing below
- ifcmd10a:cmp bx,iflgt ; IF LGT?
- jne ifcmd10b ; ne = no
- jmp ifequ
- ifcmd10b:cmp bx,ifllt ; IF LLT?
- jne ifcmd11 ; ne = no
- jmp ifequ
-
- ifcmd11:cmp bx,ifless ; IF <?
- je ifcmd12 ; e = yes
- cmp bx,ifsame ; IF =?
- je ifcmd12
- cmp bx,ifmore ; IF > ?
- jne ifcmdf ; ne = no
- ifcmd12:jmp ifmath
-
- ; Jump points for worker routines
- ; failure
- ifcmdf: cmp notflag,0 ; need to apply not condition?
- jne ifcmdp2 ; ne = yes, take other exit
- ifcmdf2:mov ah,cmline ; fail, read and discard rest of line
- mov comand.cmblen,cmdblen
- mov bx,offset rdbuf
- mov dx,offset discard ; say not doing anything
- mov comand.cmper,1 ; don't expand variables at this time
- call comnd
- clc ; force success on discard of line
- ret
- ; success (pass)
- ifcmdp: cmp notflag,0 ; need to apply not condition?
- jne ifcmdf2 ; ne = yes, take other exit
- ifcmdp2:clc ; do command
- ret
- IFCMD ENDP
-
- ; Compare errlev against user number. Jump successfully if errlev >= number.
- ; Worker for IF [NOT] ERRORLEVEL number <command>
- ifnum proc near
- mov ah,cmword ; get following number
- mov dx,offset rdbuf+1
- mov comand.cmblen,cmdblen
- mov rdbuf,'\' ; in case user forgets backslash
- mov word ptr rdbuf+1,0 ; clear buffer
- mov bx,offset ifnhlp ; help
- call comnd
- jnc ifnum1 ; nc = success
- ret ; failure
- ifnum1: mov si,offset rdbuf ; put text in compare buffer
- cmp rdbuf+1,'\' ; did user include backslash?
- jne ifnum2 ; ne = no
- inc si ; yes, skip our helpful backslash
- ifnum2: call katoi ; convert number to binary in ax
- jc ifnum4 ; c = failed to convert a number
- cmp errlev,al ; at or above this level?
- jae ifnum3 ; ae = yes, succeed
- jmp ifcmdf ; else fail
- ifnum3: jmp ifcmdp ; jump to main command Success exit
-
- ifnum4: mov dx,offset rdbuf+1 ; pointer to bad word
- mov tempd,dx ; remember starting place for text
- call strlen ; get its length
- add dx,cx ; skip over current word
- mov bx,dx
- mov byte ptr [bx],' ' ; space, chopped by parser
- inc bx ; new text goes here
- xor dx,dx ; help
- mov ah,cmline ; read rest of line
- mov comand.cmblen,cmdblen
- call comnd
- jnc ifnum4a ; nc = success
- ret ; failure
- ifnum4a:or ax,ax ; returned byte count
- jnz ifnum5 ; nz = got some
- mov byte ptr[bx-1],0 ; remove space separator from above
- ifnum5: mov ah,prstr
- mov dx,offset ifnmsg ; error message header
- int dos
- mov dx,offset rdbuf+1 ; start of user text
- call prtasz ; display asciiz string
- mov ah,prstr
- mov dx,offset ifnmsg2 ; trailer of message
- int dos
- jmp ifcmdf ; jump to main command Failure exit
- ifnum endp
-
- ; Process IF [NOT] DEF <macro name> <command>
- ifmdef proc near
- mov dx,offset rdbuf+2 ; point to work buffer
- mov bx,offset ifdfhlp ; help
- mov comand.cmblen,cmdblen
- mov ah,cmword ; get macro name
- mov comand.cmper,1 ; do not react to \%x
- call comnd
- jnc ifmde1 ; nc = success
- ret ; failure
- ifmde1: mov word ptr rdbuf,ax ; store length in buffer
- mov bx,offset mcctab+1 ; table of macro keywords
- mov tempd,0 ; tempd = current keyword
- cmp byte ptr [bx-1],0 ; any macros defined?
- je ifmde9 ; e = no, failure, exit now
- ; match table keyword and user word
- ifmde3: mov si,offset rdbuf ; pointer to user's cnt+name
- mov cx,[si] ; length of user's macro name
- add si,2 ; point to macro name
- cmp cx,[bx] ; compare length vs table keyword
- jne ifmde7 ; ne = not equal lengths, try another
- push si ; lengths match, how about spelling?
- push bx
- add bx,2 ; point at start of keyword
- ifmde4: mov ah,[bx] ; keyword char
- mov al,[si] ; new text char
- cmp al,'a' ; map lower case to upper
- jb ifmde5
- cmp al,'z'
- ja ifmde5
- sub al,'a'-'A'
- ifmde5: cmp al,ah ; test characters
- jne ifmde6 ; ne = no match
- inc si ; move to next char
- inc bx
- loop ifmde4 ; loop through entire length
- ifmde6: pop bx
- pop si
- jcxz ifmde10 ; z: cx = 0, found the name
- ; select next keyword
- ifmde7: inc tempd ; number of keyword to test next
- mov cx,tempd
- cmp cl,mcctab ; all done? Recall, tempd starts at 0
- jae ifmde9 ; ae = yes, no match
- mov ax,[bx] ; cnt (keyword length from macro)
- add ax,4 ; skip over '$' and two byte value
- add bx,ax ; bx = start of next keyword slot
- jmp short ifmde3 ; do another comparison
- ifmde9: jmp ifcmdf ; jump to main command Failure exit
- ifmde10:jmp ifcmdp ; jump to main command Success exit
- ifmdef endp
-
- ; IF [not] ALARM hh:mm:ss command
- ifalrm proc near
- call chkkbd ; check keyboard for override
- test status,stat_cc ; Control-C?
- jz ifalr1 ; z = no
- stc
- ret ; yes, return failure now
- ifalr1: push word ptr timhms
- push word ptr timhms+2 ; save working timeouts
- mov ax,word ptr alrhms
- mov word ptr timhms,ax
- mov ax,word ptr alrhms+2
- mov word ptr timhms+2,ax ; set alarm value
- call chktmo ; check for timeout
- pop word ptr timhms+2 ; restore working timeouts
- pop word ptr timhms
- test status,stat_tmo ; tod past user time (alarm sounded)?
- jnz ifalr4 ; nz = yes, succeed
- ; failure (not at alarm time yet)
- cmp notflag,0 ; need to apply NOT condition?
- jne ifalr5 ; ne = yes, take other exit
- ifalr3: mov ah,cmline ; fail, read and discard rest of line
- mov bx,offset rdbuf
- mov comand.cmblen,cmdblen
- xor dx,dx
- call comnd
- clc ; set command parse success
- ret
- ; success (at or past alarm time)
- ifalr4: cmp notflag,0 ; need to apply not condition?
- jne ifalr3 ; ne = yes, take other exit
- ifalr5: clc ; pass, do command
- ret
- ifalrm endp
-
- ; IF [NOT] {LLT, EQUAL, LGT} word word command
- ; Permits use of \number, {string}, @filespec
- ifequ proc near
- mov ltype,bl ; remember kind of lex test
- mov comand.cmblen,cmdblen
- mov ah,cmword ; get a word
- mov dx,offset rdbuf ; where to store
- mov rdbuf,0 ; clear first entry
- mov bx,offset ifehlp1 ; help
- call comnd ; ignore parse error if no text
- mov si,offset rdbuf ; start of line
- mov di,si ; convert to the same place
- call cnvlin ; convert \numbers to binary
- jc ifequ9 ; carry set means error
- jcxz ifequ9 ; z = empty word
- mov tempd,cx
- add si,cx
- inc si ; skip null terminator
- mov temptr,si ; place to start second part
- mov dx,si
- mov word ptr[si],0 ; clear second part
- mov ah,cmword ; get a word of text
- mov bx,offset ifehlp2 ; help
- mov comand.cmblen,cmdblen
- call comnd ; ignore parse error if no text
- mov si,temptr ; start of second line
- mov di,si ; convert to the same place
- call cnvlin ; convert \numbers to binary
- jc ifequ9 ; c = failure
- jcxz ifequ9 ; z = empty word
- cmp tempd,cx ; first longer than second?
- jae ifequ3 ; ae = yes
- xchg tempd,cx ; use length of shorter word
- ifequ3: inc cx ; include null terminator in count
- mov si,offset rdbuf ; first word
- mov di,temptr ; second word
- push es
- mov ax,ds
- mov es,ax
- cld
- repe cmpsb ; compare while equal
- pop es
- jb ifequ6 ; exited on before condition
- ja ifequ7 ; exited on above condition
-
- cmp ltype,ifequal ; wanted EQUAL condition?
- jne ifequ9 ; ne = no, fail
- jmp ifcmdp ; else success
-
- ifequ6: cmp ltype,ifllt ; LLT test?
- jne ifequ9 ; ne = no, failed
- jmp ifcmdp ; do IF cmd success
-
- ifequ7: cmp ltype,iflgt ; LGT test?
- jne ifequ9 ; ne = no, failed
- jmp ifcmdp ; do IF cmd success
-
- ifequ9: jmp ifcmdf ; do IF cmd failure
- ifequ endp
-
- ; Worker for IF [NOT] < = > var var <command>
- ; var is ARGC, COUNT, ERRORLEVEL, VERSION, or a 16 bit number
- ifmath proc near
- mov tempa,bl ; save kind of math test here
- mov temp,0 ; place to store first value
- mov tempd,0 ; count times around this loop
- ifmath1:mov dx,offset rdbuf+1
- mov rdbuf,'\' ; in case user forgets backslash
- mov word ptr rdbuf+1,0 ; clear buffer
- mov bx,offset ifmhlp ; help
- mov comand.cmblen,cmdblen
- mov ah,cmword ; get following number
- call comnd
- jnc ifmath2 ; nc = success
- ret ; failure
- ifmath2:mov si,offset rdbuf+1 ; put text in compare buffer
- mov ax,[si] ; get first two user chars
- or ax,2020h ; lowercase both bytes
- cmp ax,'ra' ; ARGC?
- jne ifmath3 ; ne = no
- xor ax,ax
- cmp taklev,0 ; in a Take/macro?
- je ifmath8 ; e = no, report ARGC as 0
- mov bx,takadr ; current Take structure
- mov ax,[bx].takargc ; get argument count
- jmp short ifmath8
- ifmath3:cmp ax,'re' ; ERRORLEVEL?
- jne ifmath4 ; ne = no
- mov al,errlev ; get errorlevel
- xor ah,ah
- jmp short ifmath8
- ifmath4:cmp ax,'oc' ; COUNT?
- jne ifmath5 ; ne = no
- xor ax,ax
- cmp taklev,0 ; in a Take/macro?
- je ifmath8 ; e = no, report COUNT as 0
- mov bx,takadr ; current Take structure
- mov ax,[bx].takctr ; get COUNT
- jmp short ifmath8
- ifmath5:cmp ax,'ev' ; VERSION?
- jne ifmath5a ; ne = no
- mov ax,version ; get version such as 300
- jmp short ifmath8
- ifmath5a:cmp ax,'ek' ; KEYBOARD?
- jne ifmath6 ; ne = no
- mov ax,keyboard ; get 88 or 101 for keys on keyboard
- jmp short ifmath8
- ifmath6:cmp rdbuf+1,'\' ; did user include backslash?
- je ifmath7 ; e = yes
- dec si ; no, employ our helpful backslash
- ifmath7:call katoi ; convert number to binary in ax
- jc ifmathb ; c = failed to convert a number
- ifmath8:cmp tempd,0 ; gotten second value yet?
- ja ifmath9 ; a = yes, it is in ax
- mov temp,ax ; save first value
- inc tempd ; say we have been here
- jmp ifmath1 ; do second argument
-
- ifmath9:mov bl,tempa ; kind of math test
- cmp bl,ifless ; "<"?
- jne ifmath10 ; ne = no
- cmp temp,ax ; val1 < val2?
- jb ifmathp ; b = pass
- jmp short ifmathf ; fail
- ifmath10:cmp bl,ifsame ; "="?
- jne ifmath11 ; ne = no
- cmp temp,ax ; val1 = val2?
- je ifmathp ; e = yes, pass
- jmp short ifmathf ; fail
- ifmath11:cmp temp,ax ; val2 > val1?
- ja ifmathp ; a = yes, pass
- ifmathf:jmp ifcmdf ; else fail
- ifmathp:jmp ifcmdp ; jump to main command Success exit
-
- ifmathb:jmp ifnum4 ; do common error complaint
- ifmath endp
-
- ; DECREMENT/INCREMENT variable size (default size 1)
- ; Permits variable to be \%<char> or a macro name. Non-negative results.
- decvar proc near
- mov temp,-1 ; marker to say dec
- jmp short incvar1
- decvar endp
-
- incvar proc near
- mov temp,1 ; marker to say inc
- incvar1:
- mov kstatus,ksgen ; general command failure
- mov ah,cmword ; Common code
- mov word ptr rdbuf,0 ; entry count, empty
- mov dx,offset rdbuf+2 ; reserve word 0 for entry count
- mov bx,offset chgvarhlp
- mov comand.cmper,1 ; don't react to \%x variables
- call comnd
- jnc incvar2 ; nc = success
- ret ; failure
- incvar2:or ax,ax ; necessary macro name?
- jnz incvar3 ; nz = yes
- incvar2a:stc ; no, fail
- ret
- incvar3:mov word ptr rdbuf,ax ; save length of macro name
- mov si,offset mcctab ; table of macro names
- cld
- lodsb
- mov cl,al ; number of macro entries
- xor ch,ch
- jcxz incvar2a ; z = none
- ; find variable
- incvar4:push cx ; save loop counter
- lodsw ; length of macro name to ax
- mov cx,word ptr rdbuf ; length of user's string
- cmp ax,cx ; variable name same as user spec?
- jne incvar6 ; ne = no, no match
- push ax
- push si ; save these around match test
- mov di,offset rdbuf+2 ; user's string
- incvar5:mov ah,[di]
- inc di
- lodsb ; al = mac name char, ah = user char
- and ax,not 2020h ; clear bits (uppercase chars)
- cmp ah,al ; same?
- loope incvar5 ; while equal, do more
- pop si ; restore regs
- pop ax
- jne incvar6 ; ne = no match
- pop cx ; remove loop counter
- jmp short incvar7 ; e = match
- incvar6:add si,ax ; point to next name, add name length
- add si,2 ; and string pointer
- pop cx ; recover loop counter
- loop incvar4 ; one less macro to examine
- xor ax,ax
- mov temp,ax ; indicate failure
- jmp incvar13 ; go do command confirmation
-
- incvar7:mov ax,[si-2] ; get length of variable string
- add si,ax ; point to segment of definition
- mov si,[si] ; seg of definition
- mov word ptr rdbuf+2,si ; preserve seg for later storage
- push es
- mov es,si
- mov cx,es:[0] ; length of definition
- cmp cx,9 ; "\x{65384}" is max length
- ja incvar10 ; a = too large to qualify
- mov di,offset rdbuf+4 ; copy string to regular data segment
- mov si,2 ; skip over string count word
- mov al,es:[si] ; get leading byte
- cmp al,'\' ; escaped number
- je incvar9 ; e = yes
- mov byte ptr [di],'\' ; insert escape
- inc di
- incvar9:mov al,es:[si] ; copy string to regular data segment
- mov [di],al
- inc si
- inc di
- loop incvar9
- mov byte ptr [di],0 ; asciiz
- mov si,offset rdbuf+4
- call katoi ; convert var value to binary in ax
- jc incvar10 ; c = failed
- mov word ptr rdbuf,ax ; save value here, seg in rdbuf+2
- pop es
- jmp short incvar12 ; now get step size, if any
- incvar10:pop es
- xor ax,ax
- mov temp,ax ; setup failure
- jmp short incvar13 ; do command confirmation
-
- incvar12:mov ah,cmword ; get step size, if any
- mov comand.cmblen,7 ; length of step size
- mov dx,offset rdbuf+6 ; where to put string
- mov bx,offset ssizehlp
- call comnd
- jnc incvar13
- ret
- incvar13:push ax ; save step size string length
- mov ah,cmeol
- call comnd
- pop ax
- jnc incvar14 ; nc = success
- ret
- ; now convert step size, if any
- incvar14:or ax,ax ; is length zero?
- jnz incvar15 ; nz = no, convert number to binary
- inc ax ; set default inc/dec to 1
- jmp incvar17 ; go process new value
-
- incvar15:mov si,offset rdbuf+6 ; step size string
- cmp byte ptr [si],'\' ; has "\"?
- je incvar16 ; e = yes
- dec si
- mov byte ptr [si],'\' ; insert one
- incvar16:call katoi ; ds:si to number to ax
- jnc incvar17 ; nc = a number
- ret ; fail
- ; step size is in ax
- incvar17:mov cx,word ptr rdbuf ; current value of variable
- cmp temp,0 ; inc or dec?
- jg incvar19 ; g = increment
- jl incvar18 ; l = decrement
- stc ; else fail
- ret
- incvar18:cmp ax,cx ; if would subtract too much
- jbe incvar18a ; be = ok
- stc ; a = would go below zero, fail
- ret
- incvar18a:neg ax ; change increment to negative
- add ax,cx ; add current value
- jc incvar20 ; c = ok
- stc
- ret ; fail
- incvar19:add ax,cx ; increment
- jnc incvar20
- ret ; carry means fail
-
- incvar20:mov di,offset rdbuf+4 ; place to store string
- call dec2di ; binary to ascii decimal in ds:di
- mov si,offset rdbuf+4
- sub di,si ; new string length
- mov cx,di
- cld
- push es
- mov ax,word ptr rdbuf+2 ; get segment of variable
- mov es,ax
- mov di,2
- mov es:[di-2],cx ; store new count word
- rep movsb ; copy string to variable's seg
- pop es
- mov kstatus,kssuc ; say success
- clc
- ret
- incvar endp
-
- ; SET ALARM <time, sec from now or HH:MM:SS>
- SETALRM PROC NEAR
- mov dx,offset line ; point to work buffer
- mov word ptr line,0
- mov word ptr line+2,0
- mov bx,offset alrmhlp ; help
- mov ah,cmword ; get macro name
- call comnd
- jc setal1 ; c = failure
- mov ah,cmeol ; get a confirm
- call comnd
- jc setal1 ; c = failure
- push word ptr timhms
- push word ptr timhms+2 ; save working timeouts
- mov si,offset line ; source pointer
- call inptim ; get the timeout time, sets si
- mov ax,word ptr timhms ; save time in alarm area
- mov word ptr alrhms,ax
- mov ax,word ptr timhms+2
- mov word ptr alrhms+2,ax
- pop word ptr timhms+2 ; restore working timeouts
- pop word ptr timhms
- clc
- setal1: ret
- SETALRM ENDP
-
- ; REINPUT <timeout> <match text>
- ; Reread material in serial port buffer, seeking a match with user's text
- ; pattern. If user's pattern is longer than material in buffer then read
- ; additional characters from the serial port. Use SCINP to do the main work.
-
- SCREINP PROC NEAR
- mov reinflg,1 ; say doing REINPUT, not INPUT
- jmp short input10
- SCREINP ENDP
-
- ; Input from port command, match input with text pattern
- ; Input [timeout] text
- ;
- SCINP PROC NEAR
- mov reinflg,0 ; say doing INPUT, not REINPUT
- jmp short input10
-
- input10:mov kstatus,kssuc
- mov ah,cmline ; get a whole line of asciiz text
- mov bx,offset line ; place to put text
- mov dx,offset inphlp ; help message
- call comnd ; get the pattern text
- jnc input11 ; nothing, complain
- ret ; failure
- input11:mov ah,cmeol
- call comnd
- jnc input12
- ret
- input12:cmp reinflg,0 ; Input command?
- jne input1 ; ne = no, Reinput
- cmp taklev,0 ; are we in a Take file?
- je input0 ; e = no, display linefeed
- cmp flags.takflg,0 ; are Take commands being echoed?
- je input1 ; e = no, skip display
- input0: cmp script.inecho,0 ; Input echo off?
- je input1 ; e = yes
- mov al,lf ; next line
- call scdisp ; display the char
- input1: call serini ; initialize the system's serial port
- jc input1a ; c = failure
- mov status,stat_unk ; clear status flag
- mov si,offset line ; source pointer
- call inptim ; get the timeout time, sets si
- jnc input1b ; nc = legal time value or none
- input1a:jmp input5 ; else fail on error
- input1b:mov di,offset line ; put text in compare buffer
- call cnvlin ; convert \numbers in buf line
- mov inplen,cx ; cx = number of bytes in final string
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov di,portval
- cmp [di].parflg,parnon ; parity is none?
- je input1c ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- input1c:mov di,offset line
- mov temptr,di ; pointer to pattern char
- mov temptr2,di ; and we need pointer to end of string
- add temptr2,cx ; offset of end of string
- ; setup reinput read pointer & count
- mov ax,bufwtptr ; where next new char goes
- mov bufpkptr,ax ; set peek-read pointer at oldest char
- mov ax,scpbuflen ; length of the buffer
- mov bufpkcnt,ax ; always look back one full buffer
- ; see if a pattern needs matching
- cmp inplen,0 ; empty pattern? (cnvlin sets cx=cnt)
- jne input4 ; ne = not empty
- cmp reinflg,0 ; Input command?
- je input3 ; e = yes, read and discard chars
- jmp input5 ; reinput, just exit timeout
-
- ; empty. read, display, and discard
- input3: call chkkbd ; check keyboard
- test status,stat_cc ; did user type control-c?
- jnz input3b ; nz = yes, quit
- test status,stat_cr ; did user type cr? [js]
- jz input3a ; z = no
- or status,stat_tmo ; force timeout status too
- jmp short input5 ; nz = yes, return timeout failure
- input3a:call chktmo ; check timeout
- test status,stat_tmo
- input3b:jnz input5 ; nz = timed out, quit
- call bufread ; read from serial port buffer into al
- jmp short input3 ; loop until timeout, exit timeout
-
- ; start main read and compare loop
- input4: mov di,temptr ; pointer to current pattern char
- cmp di,temptr2 ; at end of pattern?
- jae inputx ; ae = yes, return success
- call chkkbd ; check keyboard
- test status,stat_cc ; did user type Control-C?
- jnz input5 ; nz = yes, quit
- test status,stat_cr ; did user type cr? [js]
- jz input4a ; z = no
- or status,stat_tmo ; force timeout status too
- jmp short input5 ; nz = yes, return success [js]
- input4a:test status,stat_tmo+stat_ok ; user override/timeout on last read
- jnz input5 ; nz = timed out, quit
- cmp reinflg,0 ; Input command?
- jne input4b ; ne = no, a reinput cmd
- call bufread ; read from serial port buffer into al
- jc input4 ; c = nothing there, keep looking
- jmp short input4c ; analyze character
-
- input4b:call peekbuf ; reinput: peek-read from buffer
- jnc input4c ; nc = got a character into al
- test status,stat_tmo ; timeout (or examined all chars)?
- jz input4 ; z = no, keep trying
- jnz input5 ; nz = timeout getting a character
-
- ; got a char from buffer/port
- input4c:cmp al,'a' ; candidate for case conversion? [js]
- jb input4d ; b = no [js]
- cmp al,'z' ; in lower case set? [js]
- ja input4d ; a = no [js]
- and al,script.incasv ; apply case conversion mask
- input4d:mov di,temptr
- mov ah,byte ptr [di] ; get current pattern char again
- call matchr ; al=rcvd, ah=pattern, do they match?
- jc inpm ; c = no match, try substring
- inc temptr ; matched, point to next pattern char
- jmp short input4
-
- input5: or errlev,ksrecv ; set RECEIVE failure condition
- or fsta.xstatus,ksrecv ; set status
- or kstatus,ksrecv
- cmp reinflg,0 ; Input command?
- jne input6 ; ne = no
- jmp squit ; exit failure: timeout or Control-C
- input6: jmp squit1 ; skip timeout message, if any
- inputx: clc ; return success
- ret
- ; See if a trailing-subset of the matched chars + new port char can match
- ; the beginning part of the pattern. That is, if we were to simply "forget"
- ; the oldest of the matched chars and slide left the apparent port string
- ; then could we eventually find a match? Example: "Input 10 memema"
- ; gives the pattern of "memema"; suppose the received chars were "mememema".
- ; Forgetting one left-most rcv'd char at a time (two in this case) finally
- ; yields a match, from which we should continue to compare fresh port chars
- ; with successive pattern chars until either they match through all pattern
- ; chars or we encounter another break. If there is a later break, repeat this
- ; algorithm.
- ; Since we really have only the latest char from the port then pointers to
- ; the matched pattern chars are used to mimic the earlier received chars:
- ; they must have been identical to produce a match to date. The quick way
- ; to "forget" oldest received chars is to scan backward through the matched
- ; pattern chars looking for the current port char; if the first such find does
- ; not yield a matching substring then look back further.
- ; no or partial match then break
- ; di = temptr = pattern break char
- ; al = port char causing break
- ; di - offset line = # chars matched thus far
- ; avoid cpu-brand side effects with "repne scasb"
- inpm: mov tempa,al ; save port char here
- inpm1: mov tempd,di ; pattern break loc, where matching failed
- mov cx,di ; char at di does not match current port char
- sub cx,offset line ; compute count of matched bytes
- jcxz inpm4 ; z = 0 = mismatch on the initial pattern char
-
- mov al,tempa ; port char to find (in case we looped here)
- inpm2: dec di ; back up one pattern char
- mov ah,byte ptr [di]; current pattern character to consider
- call matchr ; is port char = earlier pattern char? [js]
- jnc inpm3 ; nc = equal values, go construct substring
- loop inpm2 ; do cx times, max. (length of match to date)
- jmp short inpm4 ; get here when there are no matches [js]
-
- inpm3: mov bx,tempd ; get last break location
- sub bx,di ; displacement = break - new find of port char
- mov tempd,di ; remember new location of a port-like char
- ; cx has number of chars in test substring
- dec cx ; matched one char already [jrs]
- jcxz inpm3a ; is there anything left? [jrs]
- call matstr ; does this substring match the pattern?
- jc inpm1 ; c = no match, try making substring smaller
-
- inpm3a: mov di,tempd ; sub-string matched. Use this shorter match
- mov temptr,di ; set di for exit (matstr messes up di)
- inc temptr ; matched, point to next pattern char
- jmp input4 ; continue with fresh port info
-
- inpm4: mov temptr,offset line; complete failure, restart scanning
- jmp input4 ; get something from the port
-
- ; worker for SCINP
- ; compare strings. One starts at offset line, the other starts bx bytes later.
- ; cx = # chars to compare. Return carry clear if match, else carry set.
- matstr: mov si,offset line ; start of pattern string
- matstr1:mov ah,byte ptr [si] ; pattern char
- mov al,byte ptr [si+bx] ; "old port char" (same as pattern char)
- call matchr ; check match of these two characters
- jc matstr2 ; c = no match (exit with carry flag set)
- inc si ; match, consider next pair
- loop matstr1 ; consider rest of substring (cx is counter)
- clc ; clear c bit (substrings do match)
- matstr2:ret ; preserves flags (c set = no match)
-
- ; worker for SCINP
- ; compare single characters, one in ah and the other in al. Allow the 0ffh
- ; wild card to match CR and LF individually. Return carry clear if match,
- ; or carry set if they do not match. Registers preserved.
- matchr: cmp ah,al ; do these match?
- je matchr6 ; e = yes
- cmp ah,0ffh ; the match cr/lf indicator?
- je matchr2 ; e = yes
- cmp al,0ffh ; the match cr/lf indicator?
- jne matchr5 ; ne = no match at all.
- matchr2:push ax ; save both chars again
- and ah,al ; make a common byte for testing
- cmp ah,cr
- je matchr4 ; e = cr matches 0ffh
- cmp ah,lf
- je matchr4 ; e = lf matches 0ffh
- pop ax ; recover chars
- matchr5:stc ; set carry (no match)
- ret
- matchr4:pop ax ; recover chars
- matchr6:clc ; clear carry (match)
- ret
- SCINP ENDP
-
- ; Pause for the indicated number of milliseconds, do not access comms channel
- SCMPAUSE PROC NEAR
- mov kstatus,kssuc
- mov ah,cmword ; get a word (number)
- mov dx,offset line+1 ; where to store it
- mov line,'\' ; optional number escape
- mov line+1,0 ; terminate line incase no text
- mov bx,offset mphlp ; help msg
- call comnd
- jnc scmpau1 ; nc = success
- ret
- scmpau1:mov si,offset line ; put text in compare buffer
- cmp line+1,'\' ; did user include backslash?
- jne scmpau2 ; ne = no
- inc si ; yes, skip our helpful backslash
- scmpau2:call katoi ; convert number to binary in ax
- jc scmpau3 ; c = failed to convert a number
- call pcwait ; delay number of millisec in AX
- clc
- ret
- scmpau3:mov ah,prstr
- mov dx,offset mpbad ; complain about bad number
- int dos
- mov kstatus,ksgen ; command status, failure
- stc
- ret
- SCMPAUSE ENDP
-
- ; Pause for the specified number of seconds or until a time of day
- ; Pause [seconds or hh:mm:ss]
- ;
- SCPAU PROC NEAR
- mov kstatus,kssuc
- mov ah,cmword ; get a word (number)
- mov dx,offset line ; where to store it
- mov byte ptr line,0 ; terminate line incase no text
- mov bx,offset ptshlp ; help msg
- call comnd
- jc scpau1 ; c = failure
- mov si,offset line ; source pointer
- call inptim ; parse pause time (or force default)
- jc scpau1 ; c = bad time value
- mov wtemp,0 ; no modem status to detect
- jmp swait4 ; finish in common code
- scpau1: ret ; return command failure
- SCPAU ENDP
-
- ;
- ; Wait for the indicated signal for the specified number of seconds or tod
- ; WAIT [seconds] \signal where \signal is \cd, \dsr, \ri modem status lines.
- ; Use INPUT-TIMEOUT ACTION for failures.
- ;
- SCWAIT PROC NEAR
- mov kstatus,kssuc
- mov ah,cmword ; get a word (number)
- mov dx,offset line ; where to store it
- mov byte ptr line,0 ; terminate line in case no text
- mov bx,offset ptshlp ; time help msg
- call comnd
- jnc swait0 ; nc = success
- ret
- swait0: mov wtemp,0 ; clear modem status test byte
- mov si,offset line ; source pointer
- push ax ; save length count
- call inptim ; parse pause time (or force default)
- pop ax
- jnc swait0a ; nc = good time value
- ret
- swait0a:cmp si,offset line ; was a number parsed?
- je swait1c ; e = no, reparse as modem signal
-
- swait1: mov ah,cmword ; get optional modem signal word(s)
- mov dx,offset line
- mov bx,offset wthlp ; modem signal help
- call comnd
- jnc swait1c ; nc = success
- ret
- swait1c:mov si,offset line
- mov cx,ax ; returned byte count
- or cx,cx ; number of chars to examine
- jle swait4 ; le = none
- cld
- swait1d:lodsb ; get a character
- dec cx ; reduce count remaining
- cmp al,'\' ; backslash signal introducer?
- je swait1d ; e = yes, skip it
- cmp cx,1 ; at least two chars in signal?
- jl swait3a ; l = no, bad syntax
- mov ax,[si-1] ; get first two characters
- or ax,2020h ; upper case to lower, two chars
- cmp ax,'dc' ; carrier detect?
- jne swait2 ; ne = no, try next signal
- or wtemp,modcd ; look for the CD bit
- inc si ; skip this field and separator
- dec cx ; two less chars left in the line
- jmp short swait1 ; continue the scan
- swait2: cmp ax,'sd' ; data set ready?
- jne swait3 ; ne = no
- mov al,[si+1] ; third letter
- or al,20h ; to lower case
- cmp al,'r' ; r for dsr?
- jne swait3b ; ne = no
- or wtemp,moddsr ; look for the DSR bit
- add si,2 ; skip this field and separator
- sub cx,2 ; three less chars left in the line
- jmp short swait1
- swait3: cmp ax,'tc' ; clear to send?
- jne swait3a ; ne = no
- mov al,[si+1] ; third letter
- or al,20h ; to lower case
- cmp al,'s' ; r for dsr?
- jne swait3b ; ne = no
- or wtemp,modcts ; look for the CTS bit
- add si,2 ; skip this field and separator
- sub cx,2 ; three less chars left in the line
- jmp short swait1 ; continue the scan
- swait3a:cmp ax,'ir' ; ring indicator
- jne swait3b ; ne = no, try next signal
- or wtemp,modri ; look for the RI bit
- inc si ; skip this field and separator
- dec cx ; two less chars left in the line
- jmp short swait1 ; continue the scan
- swait3b:or al,al ; null terminator?
- je swait4 ; e = yes, no more text
- mov ah,prstr
- mov dx,offset wtbad ; say bad syntax
- int dos
- or errlev,ksuser ; set user intervention error condx
- or fsta.xstatus,ksuser ; set status
- or kstatus,ksuser
- stc ; failure
- ret
- ; SWAIT4 is used by PAUSE command
- SWAIT4: mov ah,cmeol ; get command confirmation
- call comnd
- jnc swait4a
- ret ; c set is failure
- swait4a:cmp taklev,0 ; are we in a Take file
- je swait5 ; e = no, print linefeed
- cmp flags.takflg,0 ; are commands being echoed
- je swait6 ; e = no, skip this
- swait5: cmp script.inecho,0 ; Input echoing off?
- je swait6 ; e = yes
- mov al,lf ; next line
- call scdisp ; display the char
- swait6: call serini ; initialize the system's serial port
- jc swait9 ; c = failure
- mov status,stat_unk ; clear status flag
- push si
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov si,portval
- cmp [si].parflg,parnon ; parity is none?
- pop si
- je swait7 ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- swait7: cmp wtemp,0 ; anything to be tested?
- je swait8 ; e = no, just do the wait part
- call getmodem ; modem handshake status to AL
- and al,wtemp ; keep only bits to be tested
- cmp al,wtemp ; check selected status bits
- jne swait8 ; ne = not all selected bits match
- clc ; all match. take successful exit
- ret
- swait8: call chkport ; get and show any new port char
- call chkkbd ; check keyboard
- test status,stat_cc ; control-c?
- jnz swait9 ; nz = yes, quit
- call chktmo ; check tod for timeout
- test status,stat_tmo+stat_ok ; timeout or user override?
- jz swait7 ; z = no, continue to wait
- cmp wtemp,0 ; were we waiting on anything?
- jne swait9 ; ne = yes, timeout = failure
- clc ; else timeout = success
- ret
- swait9: or errlev,ksuser ; set user intervention error condx
- or fsta.xstatus,ksuser ; set status
- or kstatus,ksuser
- jmp squit ; take error exit
- SCWAIT ENDP
-
-
- ; Output line of text to port, detect \b and \B as commands to send a Break
- ; and \l and \L as a Long Break on the serial port line.
- ; Output text, display up to 100 received chars while doing so.
-
- SCOUT PROC NEAR
- mov kstatus,kssuc
- mov ah,cmline ; get a whole line of asciiz text
- mov bx,offset line ; store text here
- mov dx,offset outhlp ; help message
- call comnd
- jnc outp0d ; nc = success
- ret ; failure
- outp0d: cmp apctrap,0 ; disable from APC
- je outp0e ; e = no
- stc ; fail
- ret
- outp0e: cmp taklev,0 ; is this being done in a Take file?
- je outpu0 ; e = no, display linefeed
- cmp flags.takflg,0 ; are commands being echoed?
- je outp0a ; e = no, skip the display
- outpu0: cmp script.inecho,0 ; Input echoing off?
- je outp0a ; e = yes
- mov al,lf ; next line
- call scdisp ; display the char
- outp0a: mov al,spause ; wait three millisec or more
- add al,3
- xor ah,ah
- call pcwait ; breathing space for HDX systems
- call serini ; initialize the system's serial port
- jnc outp0c ; nc = success
- or errlev,kssend ; set SEND failure condition
- or fsta.xstatus,kssend ; set status
- or kstatus,kssend
- jmp squit
-
- outp0c: mov status,stat_unk ; clear status flag
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov si,portval
- cmp [si].parflg,parnon ; parity is none?
- je outp0b ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- outp0b: mov si,portval ; serial port structure
- mov bl,[si].ecoflg ; Get the local echo flag
- mov lecho,bl ; our copy
- mov si,offset line ; get start of line
- mov di,offset line ; put results in the same place
- mov ah,script.incasv ; save current case state
- push ax
- mov script.incasv,0ffh ; say no case conversion
- call cnvlin ; convert \numbers to binary
- pop ax
- mov script.incasv,ah ; recover case state
- jnc outpu1 ; nc = no error
- ret ; return on error
- outpu1: mov temptr,offset line ; save pointer here
- mov tempd,cx ; save byte count here
- mov ttyact,1 ; say interactive style output
-
- outpu2: cmp tempd,0 ; are we done?
- jg outpu2a ; g = not done yet
- mov ttyact,0 ; reset interactive output flag
- clc ; return success
- ret
- outpu2a:mov si,temptr ; recover pointer
- cld
- lodsb ; get the character
- dec tempd ; one less char to send
- mov temptr,si ; save position on line
- mov tempa,al ; save char here for outchr
- mov retry,0 ; number of output retries
- cmp al,5ch ; backslash?
- jne outpu4d ; ne = no
- mov al,[si]
- and al,not 20h ; to upper case
- cmp al,'B' ; "\B" for BREAK?
- jne outpu4l ; ne = no
- outpu4c:inc temptr ; move scan ptr beyond "\b"
- dec tempd
- call sendbr ; call msx send-a-break procedure
- jmp short outpu5 ; resume beyond echoing
- outpu4l:cmp al,'L' ; "\L" for Long BREAK?
- jne outpu4d ; ne = no
- inc temptr
- dec tempd
- call sendbl ; send a Long BREAK
- jmp short outpu5 ; resume beyond echoing
-
- outpu4d:inc retry ; count output attempts
- cmp retry,maxtry ; too many retries?
- jle outpu4g ; le = no
- or errlev,kssend ; set SEND failure condition
- or fsta.xstatus,kssend ; set status
- or kstatus,kssend
- jmp squit ; return failure
- outpu4g:
- mov ax,outpace ; millisecs pacing delay
- inc ax ; at least 1 ms
- call pcwait
- mov ah,tempa ; outchr gets fed from ah
- call outchr ; send the character to the port
- jc outpu4d ; failure to send char
- cmp lecho,0 ; is Local echo active?
- je outpu5 ; e = no
- mov al,tempa ;
- test flags.capflg,logses ; is capturing active?
- jz outp4b ; z = no
- push ax ; save char
- call cptchr ; give it captured character
- pop ax ; restore character and keep going
- outp4b: cmp script.inecho,0 ; Input echo off?
- je outpu5 ; e = yes
- call scdisp ; echo character to the screen
- ;
- outpu5: mov tempa,100+1 ; wait for max 100 chars in/out [dan]
- outpu5a:mov cx,10 ; reset retry counter
- outpu5b:push cx
- call chkkbd ; check keyboard for interruption
- pop cx
- test status,stat_cc ; control c interrupt?
- jnz outpu6 ; nz = yes, quit now
- cmp script.inecho,0 ; Input echo off?
- je outpu5c ; e = yes, skip port reading/display
- dec tempa ; reached maximum chars in yet? [dan]
- jz outpu5c ; z = yes, send character anyway [dan]
- push cx
- call chkport ; check for char at serial port
- pop cx
- test status,stat_ok ; and put any in buffer
- jnz outpu5a ; nz = have a char, look for another
- mov ax,1 ; wait 1 millisec between rereads
- push cx ; protect counter
- call pcwait
- pop cx
- dec cx ; count down retries
- jge outpu5b ; ge = keep trying
- outpu5c:jmp outpu2 ; no more input, resume command
- outpu6: or errlev,kssend ; set SEND failure condition
- or fsta.xstatus,kssend ; set status
- or kstatus,kssend
- mov ttyact,0 ; reset interactive output flag
- jmp squit ; quit on control c
- SCOUT ENDP
-
-
- ; Raw file transfer to host (strips linefeeds)
- ; Transmit filespec [prompt]
- ; Optional prompt is the single char expected from the host to ACK each line.
- ; Default prompt is a script.xmitpmt (linefeed) or a carriage return from us.
- ;
- SCXMIT PROC NEAR
- mov kstatus,kssuc
- mov ah,cmword ; get a filename, asciiz
- mov dx,offset line ; where to store it
- mov bx,offset xmthlp ; help message
- call comnd
- jnc xmit0c ; nc = success
- ret ; failure
- xmit0c: mov ah,cmword ; get a prompt string, asciiz
- mov dx,offset line+81 ; where to keep it (end of "line")
- mov bx,offset pmthlp ; Help in case user types "?".
- call comnd
- jnc xmit0d ; nc = success
- ret ; failure
- xmit0d: mov line+80,al ; length of user's string
- mov ah,cmeol ; confirm
- call comnd
- jnc xmit0e
- ret
- xmit0e: cmp line,0 ; filename given?
- je xmit0a ; e = no
- mov si,offset line+81 ; convert possible numeric prompt
- cmp byte ptr [si-1],0 ; anything given?
- jz xmit0 ; z = no, use default
- call katoi ; convert number to binary, if number
- jnc xmit0b ; nc = got number
- mov al,line+81 ; get ascii char from user's prompt
- xmit0b: mov script.xmitpmt,al ; set prompt
- xmit0: mov dx,offset line ; point to filename
- mov ah,open2 ; DOS 2 open file
- xor al,al ; open for reading
- int dos
- mov fhandle,ax ; store file handle here
- mov temp,0 ; counts chars/line
- jnc xmit1 ; nc = successful opening
-
- xmit0a: mov ah,prstr ; give file not found error message
- mov dx,offset xfrfnf
- int dos
- or errlev,kssend ; set SEND failure condition
- or fsta.xstatus,kssend ; set status
- or kstatus,kssend
- jmp squit ; exit failure
-
- xmitx: mov ah,prstr ; error during transfer
- mov dx,offset xfrrer
- int dos
- xmitx2: mov bx,fhandle ; file handle
- mov ah,close2 ; close file
- int dos
- call bufclear ; clear script buffer
- call clrbuf ; clear local serial port buffer
- or errlev,kssend ; set SEND failure condition
- or fsta.xstatus,kssend ; set status
- or kstatus,kssend
- jmp squit ; exit failure
- ;
- xmity: mov bx,fhandle ; file handle
- mov ah,close2 ; close file
- int dos
- call bufclear ; clear buffers
- call clrbuf
- clc ; and return success
- ret
- xmit1: call serini ; initialize serial port
- jnc xmit1b ; nc = success
- or errlev,kssend ; set SEND failure condition
- or fsta.xstatus,kssend ; set status
- or kstatus,kssend
- jmp squit
-
- xmit1b: call bufclear ; clear script input buffer
- call clrbuf ; clear serial port buffer
- mov status,stat_unk ; clear status flag
- mov parmsk,0ffh ; parity mask, assume 8 bit data
- mov si,portval
- cmp [si].parflg,parnon ; parity is none?
- je xmit1a ; e = none
- mov parmsk,07fh ; else strip parity (8th) bit
- xmit1a: mov bl,[si].ecoflg ; get the local echo flag
- mov lecho,bl ; our copy
- mov dx,offset crlf ; display cr/lf
- mov ah,prstr
- int dos
-
- xmit2: mov dx,offset line ; buffer to read into
- mov cx,linelen ; # of bytes to read
- mov ah,readf2 ; read bytes from file
- mov bx,fhandle ; file handle is stored here
- int dos
- jnc xmit2a ; nc = success
- jmp xmitx ; exit failure
- xmit2a: mov cx,ax ; number of bytes read
- jcxz xmity ; z = none, end of file
- mov si,offset line ; buffer for file reads
- cld
- xmit3: lodsb ; get a byte
- cmp al,ctlz ; is this a Control-Z?
- jne xmit3a ; ne = no
- cmp flags.eofcz,0 ; ignore Control-Z as EOF?
- je xmit3a ; e = yes
- jmp xmity ; ne = no, we are at EOF
- xmit3a: push si ; save position on line
- push cx ; and byte count
- cmp al,cr ; CR, end of line?
- jne xmit3b ; ne = no
- cmp temp,0 ; chars sent in this line, any?
- ja xmit3c ; a = sent some
- cmp script.xmitfill,0 ; fill empty lines?
- je xmit3c ; e = no, send the cr
- mov al,script.xmitfill ; empty line fill char
- pop cx
- pop si
- dec si ; backup read pointer to CR again
- inc cx ; count filler as line information
- push si
- push cx
- jmp short xmit3c
- xmit3b: cmp al,lf ; line feed?
- jne xmit3c ; ne = no
- cmp script.xmitlf,0 ; send LF's?
- je xmit7 ; e = no, don't send it
- mov temp,-1 ; -1 so inc returns 0 after send
- xmit3c: push ax ; save char around outchr call
- mov retry,0 ; clear retry counter
- xmit4f: pop ax ; recover saved char
- push ax ; and save it again
- mov ah,al ; outchr wants char in ah
- inc retry ; count number of attempts
- cmp retry,maxtry ; too many retries?
- jle xmit4g ; le = no
- or status,stat_cc ; simulate control-c abort
- pop ax ; clean stack
- xor al,al ; clear char
- jmp short xmita ; and abort transfer
- xmit4g: call outchr ; send the character to the port
- inc temp ; count chars sent in this line
- jc xmit4f ; c failed, try again
- xmit4h: pop ax ; recover saved char
- cmp lecho,0 ; is local echoing active?
- je xmit5 ; e = no
- test flags.capflg,logses ; capturing active?
- jz xmit4a ; z = no
- call cptchr ; give it the character just sent
- xmit4a: call scdisp ; display char on screen
-
- xmit5: cmp al,cr ; did we send a carriage return?
- je xmit8 ; e = yes, time to check keyboard
-
- xmit7: pop cx
- pop si
- dec cx
- or cx,cx
- jle xmit7a ; le = finished this line
- jmp xmit3 ; finish this buffer full
- xmit7a: jmp xmit2 ; read next buffer
-
- xmit8: test status,stat_cc ; Control-C seen?
- jnz xmita ; nz = yes
- mov temp,0 ; say starting new char/line count
- call chkkbd ; check keyboard (returns char in al)
- test status,stat_ok ; have a char?
- jnz xmita ; nz = yes
- cmp script.xmitpmt,0 ; is prompt char a null?
- jne xmit8b ; ne = no
- call bufread ; check for char from serial port buf
- jnc xmit8 ; nc = a char, read til none
- jmp short xmit8c ; continue transfer
- xmit8b: call bufread ; check for char from serial port buf
- jc xmit8 ; c = none
- cmp al,script.xmitpmt ; is port char the ack?
- jne xmit8 ; ne = no, just ignore the char
- xmit8c: mov ax,script.xmitpause ; get millisecs to pause
- or ax,ax ; any time?
- jz xmit7 ; z = none
- call pcwait ; wait this long
- jmp short xmit7 ; yes, continue transfer
-
- xmita: test status,stat_cc ; Control-C?
- jnz xmitc ; nz = yes
- test status,stat_cr ; a local ack?
- jz xmit8 ; z = no, ignore local char
- mov dx,offset crlf ; display cr/lf
- mov ah,prstr
- int dos
- jmp xmit8c ; continue transfer
- xmitc: pop cx ; Control-C, clear stack
- pop si ; ...
- mov dx,offset xfrcan ; say canceling transfer
- mov ah,prstr
- int dos
- mov flags.cxzflg,0 ; clear Control-C flag
- jmp xmitx2 ; ctrl-c, quit
-
- SCXMIT ENDP
-
- ;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
- ;
- ;worker: copy line from si to di, converting \nnn strings to single chars
- ; returns carry set if error, else carry clear. Detects leading at-sign
- ; as an indicator to read command file for one line of text; command files
- ; may be nested to a depth of 100.
- ; Items of the form \chars which are not numbers are copied verbatium
- ; to the output string (ex: \a is copied as \a). The string is first trimmed
- ; of trailing spaces, then the possible curly brace delimiter pair is
- ; removed, and finally \numbers are converted to binary. [jrd]
- cnvlin proc near
- push tempd
- push es
- push si ; source ptr
- push di ; destination ptr
- push ds
- pop es ; use data segment for es:di
- mov tempd,0 ; count indirection depth
- cnvln0: cmp tempd,100 ; limit to 100 deep
- jbe cnvln0a ; be = not too deep yet
- jmp cnvln8 ; too deep, quit
- cnvln0a:cld
- xor cx,cx ; initialize returned byte count
- lodsb ; get the first character
- cmp al,40h ; at-sign indirection?
- je cnvln5 ; e = yes, open the file
- dec si ; no, push back char just read
- call cnvstr ; convert string's curly braces
- cnvln1: xor ah,ah ; clear high byte of number
- call katoi ; get a char into al, convert number
- jnc cnvln4 ; nc = binary number converted
- cmp al,0ffh ; cr/lf wild card?
- je cnvln4 ; e = yes, store it
- or al,al ; end of line?
- jnz cnvln3 ; nz = no
- jmp cnvlnx ; yes, exit now
- cnvln3: cmp al,'a' ; candidate for conversion? [js]
- jb cnvln4 ; b = no
- cmp al,'z' ; still in lower case set? [js]
- ja cnvln4 ; a = no
- and al,script.incasv ; else apply case conversion mask
- cnvln4: stosb ; save the char
- inc cx ; and count it
- or ah,ah ; was number larger than one byte?
- jz cnvln1 ; z = no
- xchg ah,al ; put high byte into al
- stosb ; store it too
- inc cx ; count storage
- jmp short cnvln1 ; read more
-
- cnvln5: mov dx,si ; get filename ptr from source line
- push si
- inc tempd ; count indirection depth
- mov cx,64 ; max length of a filename.
- cnvln5a:cmp byte ptr [si],' ' ; whitespace or control code?
- jbe cnvln5b ; be = yes, found termination
- inc si ; else look at next char
- loop cnvln5a ; limit search
- cnvln5b:mov byte ptr [si],0 ; make asciiz
- pop si
- mov ah,open2 ; DOS 2 open file
- xor al,al ; open for reading
- int dos
- mov word ptr fhandle,ax ; store file handle
- jnc cnvln7 ; nc = open ok, read from file
-
- mov ah,prstr
- mov dx,offset indmis ; file open error msg
- int dos
- xor cx,cx ; say zero bytes read
- pop di ; destination ptr
- pop si ; source ptr
- pop es
- pop tempd
- stc ; set c bit, failure
- ret
-
- cnvln7: mov bx,word ptr fhandle ; file handle
- mov cx,linelen ; # of bytes to read
- mov ah,ioctl ; ioctl, is this the console device?
- xor al,al ; get device info
- int dos
- and dl,81h ; ISDEV and ISCIN bits needed together
- cmp dl,81h ; Console input device?
- jne cnvln7d ; ne = no, use regular file i/o
- push ds
- pop es ; set es:di to data segment
- push di ; save starting pointer
- cnvln7b:mov ah,coninq ; read console, no echo
- int dos
- stosb
- cmp al,cr ; end of the line yet?
- loopne cnvln7b ; keep reading
- mov byte ptr [di],0 ; insert terminator
- pop di ; recover starting pointer
- mov dx,di ; simulate read file read
- mov ax,linelen
- sub ax,cx ; ax = number of chars read
- jmp short cnvln7e ; close file, finish processing
-
- cnvln7d:mov dx,di ; destination ptr
- mov byte ptr [di],0 ; insert null terminator, clears line
- mov ah,readf2 ; DOS 2 read from file
- int dos
- cnvln7e:pushf ; save flags
- push ax ; save byte count read
- mov ah,close2 ; close file (wanted just one line)
- int dos
- pop ax
- popf ; recover flags now
- jc cnvln8 ; c = error
- mov cx,ax ; ax = number of bytes read
- jcxz cnvln8a ; cx = z = no bytes read
- mov al,cr ; look for cr as terminator
- cld
- repne scasb ; scan while not a cr and cx not zero
- jne cnvln7a ; ne = no cr found
- dec di ; point at cr
- cnvln7a:mov byte ptr [di],0 ; plant terminator on the cr
- ; or after last read char, if no cr.
- pop di ; get original destination ptr
- push di ; and save it again
- mov si,dx ; new source = this line
- ; go convert text, as necessary, and
- jmp cnvln0 ; allow nested indirection
-
- cnvln8: mov ah,prstr
- mov dx,offset inderr ; error reading file message
- int dos
- cnvln8a:xor cx,cx ; say zero bytes read
- pop di
- pop si
- pop es
- pop tempd
- stc ; set carry for failure
- ret ; and do a real return
-
- cnvlnx: pop di ; destination ptr
- pop si ; source ptr
- pop es
- pop tempd
- clc ; clear c bit, success
- ret
- cnvlin endp
- ;
- ; worker: read the number of seconds to pause or timeout
- ; returns time of day for timeout in timhms, and next non-space or
- ; non-tab source char ptr in si. Time is either elapsed seconds or
- ; a specific hh:mm:ss, determined from context of colons being present.
- ; Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
- ; hh:mm:ss form has bad construction (invalid time).
- inptim proc near
- push ax
- push bx
- push cx
- push dx
- push di
- cld ; decode pure seconds construction
- mov di,si ; remember source pointer
- mov cx,10 ; multiplier
- mov bx,script.indfto ; no numbers yet, use default-timeout
- mov al,byte ptr[si]
- cmp al,':' ; stray hh:mm:ss separator?
- je inptm8 ; e = yes
- cmp al,'9' ; start with numeric input?
- ja inptm4 ; a = no, use default time
- cmp al,'0' ; ditto
- jb inptm4
- xor ah,ah ; source char holder
- xor bx,bx ; accumulated sum
- inptm1: mov al,byte ptr[si] ; get a byte into al
- cmp al,':' ; hh:mm:ss construction?
- je inptm8 ; e = yes
- sub al,'0' ; remove ascii bias
- cmp al,9 ; numeric?
- ja inptm4 ; a = non-numeric, exit loop, bx = sum
- xchg ax,bx ; put sum into ax, char in bl
- mul cx ; sum times ten
- xchg ax,bx ; put char into al, sum in bx
- add bx,ax ; add to sum
- inc si ; next char
- jmp short inptm1 ; loop thru all chars
-
- inptm4: cmp bx,12*60*60 ; half a day, in seconds
- jb inptm5 ; b = less than
- jmp inptm13 ; more than, error
- inptm5: push si ; save ending scan position for return
- mov timout,bx ; # seconds of timeout desired
- mov ah,gettim ; read DOS tod clock
- int dos
- mov timhms[0],ch ; hours
- mov timhms[1],cl ; minutes
- mov timhms[2],dh ; seconds
- mov timhms[3],dl ; hundredths of seconds
- mov bx,2 ; start with seconds field
- inptm6: mov ax,timout ; our desired timeout interval
- add al,timhms[bx] ; add current tod digit to interval
- adc ah,0
- xor dx,dx ; clear high order part thereof
- mov cx,60 ; divide by 60
- div cx ; compute number of minutes or hours
- mov timout,ax ; quotient
- mov timhms[bx],dl ; put remainder in timeout tod digit
- dec bx ; look at next higher order time field
- or bx,bx ; done all time fields?
- jge inptm6 ; ge = no
- cmp timhms[0],24 ; normalize hours
- jl inptm7 ; l = not 24 hours
- sub timhms[0],24 ; discard part over 24 hours
- inptm7: pop si ; return ptr to next source char
- jmp short inptm11 ; trim trailing whitespace
-
- inptm8: ; decode hh:[mm[:ss]] to timhms
- mov si,di ; recall starting source pointer
- mov word ptr timhms[0],0 ; clear time out tod
- mov word ptr timhms[2],0
- xor bx,bx ; three groups possible
- inptm9: mov dl,byte ptr[si] ; get a char
- cmp dl,':' ; field separator?
- je inptm10 ; e = a separator, step fields
- sub dl,'0' ; remove ascii bias
- cmp dl,9
- ja short inptm11 ; a = failure to get expected digit
- mov al,timhms[bx] ; get sum to al
- mov ah,10
- mul ah ; sum times ten
- add al,dl ; sum = 10 * previous + current
- mov timhms[bx],al ; current sum
- cmp timhms[bx],60 ; more than legal?
- jae inptm13 ; ae = illegal
- or bx,bx ; doing hours?
- jnz inptm9a ; nz = no, min or sec
- cmp timhms[bx],24 ; more than legal?
- jae inptm13 ; ae = illegal
- inptm9a:inc si ; next char
- jmp short inptm9 ; continue analysis
- inptm10:inc bx ; point to next field
- inc si ; next char
- cmp bx,2 ; last subscript to use (secs)
- jbe inptm9 ; be = get more text
-
- inptm11:cmp byte ptr [si],spc ; examine break char, remove spaces
- jne inptm12 ; ne = no, stay at this char
- inc si ; look at next char
- jmp short inptm11 ; continue scanning off white space
- inptm12:clc ; carry clear for success
- jnc inptm14
- inptm13:stc ; carry set for illegal value
- inptm14:pop di ; return with si beyond our text
- pop dx
- pop cx
- pop bx
- pop ax
- ret
- inptim endp
-
- ; worker: display the char in al on screen
- ; use caret-char notation for control codes
- scdisp proc near
- push dx
- push ax
- mov ah,conout ; our desired function
- test flags.remflg,d8bit ; show all 8 bits?
- jnz scdisp0 ; nz = yes
- and al,7fh ; apply 7 bit display mask
- scdisp0:or al,al ; null?
- jz scdis2 ; z = yes, ignore
- cmp al,del ; delete code?
- je scdis2 ; e = yes, ignore
- cmp al,spc ; control char?
- jae scdis1 ; ae = no, display as-is
- cmp al,cr ; carriage return?
- je scdis1 ; e = yes, display as-is
- cmp al,lf ; line feed?
- je scdis1
- cmp al,tab ; horizontal tab?
- je scdis1
- cmp al,bell ; bell?
- je scdis1
- cmp al,bs ; backspace?
- je scdis1
- cmp al,escape ; escape?
- je scdis1
- or al,40h ; control code to printable char
- push ax
- mov dl,5eh ; display caret first
- int dos
- pop ax
- scdis1: mov dl,al ; the char to be displayed
- int dos
- scdis2: pop ax
- pop dx
- ret
- scdisp endp
-
- ; workers
- ; Circular buffer for data from serial port. Written by Joe R. Doupnik
- ; Entry points -
- ; bufread: read serial port for latest char (invokes bufwrite, sets
- ; status), get a char into al, return carry set if none.
- ; bufwrite: put a char from al into buf. If this overwrites an unread
- ; character then: we lose the old char, the read pointer
- ; is moved to the next oldest unread char, and the
- ; number of chars in the buffer is decreased by one.
- ; bufclear: empties the buffer.
- ; The buffer is prtbuf, of size scpbuflen bytes. Internally, integer bufcnt
- ; holds the number of buffer locations occupied, pointer bufrdptr is the
- ; offset of the char to be read, pointer bufwtptr is the offset of the
- ; place to store the next incoming char.
- ;
- bufclear proc near
- xor ax,ax ; create a zero
- mov bufcnt,ax ; clear count of bytes in buffer
- mov bufrdptr,ax ; move read pointer to start of buf
- mov bufwtptr,ax ; move write pointer to start of buf
- mov cx,scpbuflen
- push es ; physically clear the buffer
- push di
- mov ax,bufseg ; segment of port buffer
- mov es,ax
- xor al,al ; write scpbuflen nulls
- xor di,di
- cld
- shr cx,1 ; do an odd byte now
- jnc bufcle1 ; nc = no odd byte
- stosb
- bufcle1:rep stosw ; do double bytes (words)
- pop di
- pop es
- ret
- bufclear endp
-
- bufread proc near
- call chkport ; get any oldest char from port
- call chktmo ; check tod for timeout
- cmp bufcnt,0 ; empty buffer?
- jne bufrd1 ; ne = no
- stc ; yes, set carry flag (no char)
- ret ; and quit (chkport sets status)
- bufrd1: push si
- push es
- mov si,bufseg ; get buffer segment
- mov es,si
- mov si,bufrdptr
- mov al,es:[si] ; extract a char into al
- inc bufrdptr ; move pointer to next byte
- dec bufcnt ; say have extracted a char
- mov si,scpbuflen
- cmp bufrdptr,si ; beyond end?
- jb bufrd2 ; b = not yet, just return
- mov bufrdptr,0 ; reset to start of buf (wrapping)
- bufrd2: pop es
- pop si
- clc ; clear carry flag (have read a char)
- ret ; chkport sets status
- bufread endp
-
- ; Non-destructive read of serial port circular buffer. Requires external
- ; initialization of peek read pointer bufpkptr and count remaining bufpkcnt.
- ; Returns character in register al.
- peekbuf proc near
- cmp bufpkcnt,0 ; peek counter, empty buffer?
- jne peekbu2 ; ne = no, so look in buffer
- or status,stat_tmo ; force timeout status
- push si
- mov si,scpbuflen
- cmp bufcnt,si ; is real buffer full?
- pop si
- jae peekbu1 ; ae = yes, have examined everything
- call chkport ; get a char from port
- and status,not stat_tmo ; clear timeout
- call chktmo ; and check for timeout
- cmp bufcnt,0 ; still nothing from port?
- je peekbu1 ; e = no char, report fact
- inc bufpkcnt ; got one, increase peek counter
- jmp short peekbu2 ; go extract it
- peekbu1:stc ; return nothing to see
- ret
- peekbu2:push si
- push es
- mov si,bufseg ; segment of port buffer
- mov es,si
- mov si,bufpkptr ; buffer peek pointer
- mov al,es:[si] ; extract a char into al
- inc bufpkptr ; move pointer to next byte
- dec bufpkcnt ; say have extracted a char
- mov si,scpbuflen
- cmp bufpkptr,si ; beyond end?
- jb peekbu3 ; b = not yet, just return
- mov bufpkptr,0 ; reset to start of buf (wrapping)
- peekbu3:pop es
- pop si
- clc ; clear carry flag (have read a char)
- ret
- peekbuf endp
-
- bufwrite proc near
- push si
- push es
- mov si,bufseg ; segment of buffer
- mov es,si
- mov si,bufwtptr
- mov es:[si],al ; store char held in al
- inc bufwtptr ; move pointer to next byte
- mov si,scpbuflen ; length of buffer
- cmp bufwtptr,si ; beyond end?
- jb bufwt1 ; b = not yet
- mov bufwtptr,0 ; reset to start of buf (wrapping)
- bufwt1: inc bufcnt ; say have added a char to the buf
- cmp bufcnt,si ; more than we can hold?
- jbe bufwt3 ; be = not overflowing
- push bufwtptr ; read ptr can't alias write ptr
- pop bufrdptr ; move up read pointer
- mov bufcnt,si ; limit count to max buffer length
- bufwt3: pop es
- pop si
- ret
- bufwrite endp
-
- ; Report buffer status for dumping buffer to a log file.
- ; Yield ax, cx, es, si as indicated below.
- buflog proc near
- mov ax,bufcnt ; number of unread chars
- mov cx,scpbuflen ; length of buffer
- mov si,bufseg ; segment of buffer
- mov es,si
- mov si,bufrdptr ; where to read next char
- ret ; return these registers
- buflog endp
-
- ; worker: check for timeout, return status=stat_tmo if timeout, else bit
- ; stat_tmo is cleared.
- chktmo: and status,not stat_tmo
- mov ah,gettim ; get the time of day
- int dos
- sub ch,timhms[0] ; hours difference, ch = (now-timeout)
- je chktmo2 ; e = same, check mmss.s
- jg chktmo1 ; g = past target hour
- add ch,24 ; we are early, see by how much
- chktmo1:cmp ch,12 ; hours difference, large or small?
- jge chktmox ; ge = not that time yet
- jl chktmo3 ; l = beyond that time
- chktmo2:cmp cl,timhms[1] ; minutes, hours match
- jb chktmox ; b = early
- ja chktmo3 ; a = late
- cmp dh,timhms[2] ; seconds, hhmm match
- jb chktmox ; b = early
- ja chktmo3 ; a = late
- cmp dl,timhms[3] ; fractions, hhmmss match
- jb chktmox ; b = early
- chktmo3:or status,stat_tmo ; say timeout
- stc
- ret
- chktmox:clc
- ret
- ;
- ; worker: check keyboard for char. Return status = stat_cc if control-C typed,
- ; stat_cr if carriage return, or stat_ok if any other char typed. Else return
- ; with these status bits cleared.
- chkkbd: and status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
- xor al,al
- cmp flags.cxzflg,'C' ; Control-C interrupt seen?
- je chkkbd0 ; e = yes
- call isdev ; is stdin a device, not disk file?
- jnc chkkbd2 ; nc = not device so do not read here
- mov ah,dconio ; keyboard char present?
- mov dl,0ffH
- int dos
- je chkkbd1 ; e = none
- or status,stat_ok ; have a char, return it in al
- cmp al,3 ; control c?
- jne chkkbd1 ; ne = not control c
- chkkbd0:or status,stat_cc ; say control c
- chkkbd1:cmp al,cr ; carriage return? [js]
- jne chkkbd2 ; ne = no
- or status,stat_cr ; say carriage return [js]
- chkkbd2:ret
- ;
- ; worker: check serial port for received char. Return status = stat_ok if
- ; char received, otherwise stat_ok cleared. Can echo char to screen. Will
- ; write char to local circular buffer.
- chkport:and status,not stat_ok ; clear status bit
- call prtchr ; char at port (in al)?
- jnc chkpor1 ; nc = yes, analyze it
- ret ; no, return
- chkpor1:and al,parmsk ; strip parity, if any
- cmp rxtable+256,0 ; is translation turned off?
- je chkpor0 ; e = yes, no translation
- push bx ; translate incoming character
- mov bx,offset rxtable ; the translation table
- xlatb
- pop bx
- chkpor0:test flags.capflg,logses ; capturing active?
- jz chkpor3 ; z = no
- test flags.remflg,d8bit ; keep 8 bits for displays?
- jnz chkpo0a ; nz = yes, 8 bits if possible
- cmp flags.debug,0 ; is debug mode active?
- jne chkpo0a ; ne = yes, record 8 bits
- and al,7fh ; remove high bit
- chkpo0a:push ax ; save char
- call cptchr ; give it captured character
- pop ax ; restore character and keep going
- chkpor3:test flags.remflg,d8bit ; keep 8 bits for displays?
- jnz chkpo3a ; nz = yes, 8 bits if possible
- and al,7fh ; remove high bit
- chkpo3a:cmp script.inecho,0 ; input echoing off?
- je chkpor4 ; e = yes
- call scdisp ; display the char
- chkpor4:call bufwrite ; put char in buffer
- or status,stat_ok ; say have a char (still in al)
- ret
- ;
- ; Squit is the script error exit pathway.
- ;
- squit: cmp flags.cxzflg,'C' ; Control-C interrupt seen?
- je squit5 ; e = yes
- test status,stat_tmo ; timeout?
- jz squit2 ; z = no, another kind of failure
- cmp taklev,0 ; in a Take/macro?
- jne squit1 ; ne = yes, skip timeout message
- push dx
- mov dx,offset tmomsg ; say timed out
- mov ah,prstr
- int dos ; display it
- pop dx
- squit1: cmp script.inactv,0 ; action to do upon timeout
- je squit4 ; 0 = proceed, ne = non-zero = quit
- squit5: call takclos ; close Take file or macro
- squit2: call isdev ; stdin is a device (vs file)?
- jc squit3 ; c = device, not a file
- mov flags.extflg,1 ; set Kermit exit flag
- squit3: cmp flags.cxzflg,'C' ; Control-C interrupt seen?
- jne squit6 ; ne = no
- or kstatus,ksuser ; say user intervention
- squit6: stc
- ret ; return failure
- squit4: clc ; return success, ignore error
- ret
- code ends
- end
-